#include "XmlInputStream.h"

using xml::XmlUtils;

xml::XmlInputStream::XmlInputStream(const char *fileName)
{
	active = true;
	if((inputFile = std::fopen(fileName, "r")) == NULL)
	{
		std::cerr<<"File "<<fileName<< " not found...\n";
		active = false;		
	}	
}
xml::XmlInputStream::~XmlInputStream()
{
	std::fclose(inputFile);
	
	std::vector<XmlUtils::_xmlToken>::iterator it = tokens.begin();
	
	int i=0;
	/*
	while (it != tokens.end())
	{
		delete [](void* )(it->ptr);
		it->ptr = 0;
		it++;		
		++i;
	}
	*/
	tokens.clear();
}

xml::XmlInputStream xml::XmlInputStream::operator>>(xml::XmlData &xml)
{
	if(!active)
		return (*this);

	char c;
	std::vector <char> token;

	char *ptr;
	int state = 0, level = 0, size = -1;



	while(std::fscanf(inputFile, "%c", &c) != EOF)
	{
		switch(c)
		{
		case '<':
			state = XmlUtils::state_matrix[state][XmlUtils::SQUARE_BRACKET_OPEN];
			break;
		case '>':
			state = XmlUtils::state_matrix[state][XmlUtils::SQUARE_BRACKET_CLOSE];
			break;
		case '/':
			state = XmlUtils::state_matrix[state][XmlUtils::SLASH];
			break;
		case ' ': case '\n' : case '\t' : case '\f':
			continue;
		default:
			state = XmlUtils::state_matrix[state][XmlUtils::ANY];			
		}

		size = token.size()+1;
		switch (state)
		{

		case XmlUtils::ROOT_IN: 
		case XmlUtils::INSIDE_TAG:
			token.push_back(c);
			break;
		
		case XmlUtils::SQUARE_BRACKET_IN:
			{			
			if(size == 1)
				break;
			ptr = new char[size];
			for(unsigned int i=0; i<token.size(); ++i)
				ptr[i] = token[i];
			ptr[token.size()] = 0;
			XmlUtils::_xmlToken t;
			t.type = XmlUtils::CONTENT;
			t.ptr = ptr;
			tokens.push_back(t);
			token.clear();
			++level;
			}
			break;
		
		case XmlUtils::SQUARE_BRACKET_OUT:
			{
			if(size == 1)
				break;
			ptr = new char[size];
			for(unsigned int i=0; i<token.size(); ++i)
				ptr[i] = token[i];
			ptr[token.size()] = 0;
			XmlUtils::_xmlToken t;
			t.type = XmlUtils::TAG;
			t.ptr = ptr;
			tokens.push_back(t);
			token.clear();
			}
			break;
		case XmlUtils::SLASH_INSIDE_TAG:
			token.push_back(c);
			--level;
			break;
		case XmlUtils::ERROR:
			break;
		}		
	}
	build_xml_data();
	xml.setRoot(this->root);	
	return (*this);
}


int i, size;

xml::XmlNode *xml::XmlInputStream::build_xml_node()
{
	if(size == 0)
		return 0;

	xml::XmlNode *node = new xml::XmlNode();

	char *tag = tokens[i].ptr;


	++i;
	while(i < size - 1 && strcmp(tag, tokens[i].ptr+1))
	{
		if(tokens[i].type == xml::XmlUtils::TAG)
			node->children.push_back(build_xml_node());
		else
			if(tokens[i].type == xml::XmlUtils::CONTENT)
				node->content.push_back(tokens[i].ptr);
		++i;
	}	
	node->tag.push_back(tag);	
	return node;
}


void xml::XmlInputStream::build_xml_data()
{
	i = 0;
	size = tokens.size();
	root = build_xml_node();	
}